﻿using Moki.Exceptions;
using Moki;
using Moki.Tests.Model;
using NUnit.Framework;

namespace Moki.Specification
{
    [TestFixture]
    public class VerifyMessageSpec
    {
        [TearDown]
        public void TearDown()
        {
            Mock.CleanUp();
        }   

        [Test]
        [ExpectedException(typeof(VerifyException))]
        public void Verify_was_called_should_return_not_called_message()
        {
            ITests test = Mock.Create<ITests>();

            Mock.VerifyCalledWithAnyArgs(() => test.DoSomething());
        }

        [Test]
        [ExpectedException(typeof(VerifyException), ExpectedMessage = "Argh!", MatchType = MessageMatch.StartsWith)]
        public void Verify_was_called_should_return_custom_message()
        {
            ITests test = Mock.Create<ITests>();

            Mock.VerifyCalledWithAnyArgs(() => test.DoSomething(), "Argh!");
        }

        [Test]
        public void Verify_was_not_called()
        {
            ITests test = Mock.Create<ITests>();

            Mock.WhenCalled(() => test.GetSomething()).Returns("That works!");

            Assert.AreEqual("That works!", test.GetSomething());

            Mock.VerifyCalledWithAnyArgs(() => test.GetSomething());
            Mock.VerifyNotCalled(() => test.GetAnswer());
            Assert.Throws<VerifyException>(() => Mock.VerifyCalledWithAnyArgs(() => test.GetAnswer()));
        }

        [Test]
        public void Verify_was_called()
        {
            ITests test = Mock.Create<ITests>();

            Mock.WhenCalled(() => test.GetSomething()).Returns("That works!");

            Assert.AreEqual("That works!", test.GetSomething());

            Mock.VerifyCalledWithAnyArgs(() => test.GetSomething());
        }

        [Test]
        [ExpectedException(typeof(VerifyException))]
        public void Verify_was_called_with_arguments_throws_exception_when_no_call()
        {
            ITests test = Mock.Create<ITests>();

            Mock.WhenCalled(() => test.ConvertToLang(5)).Returns("five");
            Mock.WhenCalled(() => test.ConvertToLang(-2)).Returns("minus two");

            Mock.VerifyCalled(() => test.ConvertToLang(1));
        }

        [Test]
        public void Verify_was_set()
        {
            ITests test = Mock.Create<ITests>();

            test.Any = "Any";

            Mock.VerifySet(() => test.Any, "Any");
        }


        [Test]
        public void Verify_was_not_set()
        {
            ITests test = Mock.Create<ITests>();

            Mock.VerifyNotSet(() => test.Any);
        }


        [Test]
        public void Verify_was_called_few_times()
        {
            ITests test = Mock.Create<ITests>();

            Mock.WhenCalled(() => test.GetSomething()).Returns("abc");

            test.GetSomething();
            test.GetSomething();
            test.GetSomething();

            Mock.VerifyCalledWithAnyArgs(() => test.GetSomething(), Times.Exactly(3));
            Mock.VerifyCalledWithAnyArgs(() => test.GetSomething(), Times.AtLeast(2));
            Mock.VerifyCalledWithAnyArgs(() => test.GetSomething(), Times.AtMost(4));
        }
    }
}
